var constants = require('./constants');
var Session = require('./session');

//微信端及其他非支付宝端小程序登录

/***
 * @class
 * 表示登录过程中发生的异常
 */
var LoginError = (function() {
	function LoginError(type, message) {
		Error.call(this, message);
		this.type = type;
		this.message = message;
	}

	LoginError.prototype = new Error();
	LoginError.prototype.constructor = LoginError;

	return LoginError;
})();

/**
 * 微信登录，获取 code 和 encryptData
 */
var getWxLoginResult = function getLoginCode(callback) {
	uni.login({
		success: function(loginResult) {
			uni.getUserInfo({
				success: function(userResult) {
					callback(null, {
						code: loginResult.code,
						encryptedData: userResult.encryptedData,
						iv: userResult.iv,
						userInfo: userResult.userInfo,
					});
				},

				fail: function(userError) {
					var error = new LoginError(constants.ERR_WX_GET_USER_INFO, '获取用户信息失败，请检查网络状态');
					error.detail = userError;
					callback(error, null);
				},
			});
		},

		fail: function(loginError) {
			var error = new LoginError(constants.ERR_WX_LOGIN_FAILED, '登录失败，请检查网络状态');
			error.detail = loginError;
			callback(error, null);
		},
	});
};

var noop = function noop() {};
var defaultOptions = {
	method: 'GET',
	success: noop,
	fail: noop,
	loginUrl: null,
};

/**
 * @method
 * 进行服务器登录，以获得登录会话
 *
 * @param {Object} options 登录配置
 * @param {string} options.loginUrl 登录使用的 URL，服务器应该在这个 URL 上处理登录请求
 * @param {string} [options.method] 请求使用的 HTTP 方法，默认为 "GET"
 * @param {Function} options.success(userInfo) 登录成功后的回调函数，参数 userInfo 微信用户信息
 * @param {Function} options.fail(error) 登录失败后的回调函数，参数 error 错误信息
 */
var login = function login(options) {
	options = Object.assign({}, defaultOptions, options);

	if (!defaultOptions.loginUrl) {
		options.fail(new LoginError(constants.ERR_INVALID_PARAMS, '登录错误：缺少登录地址，请通过 setLoginUrl() 方法设置登录地址'));
		return;
	}

	var doLogin = () => getWxLoginResult(function(wxLoginError, wxLoginResult) {
		if (wxLoginError) {
			options.fail(wxLoginError);
			return;
		}

		var userInfo = wxLoginResult.userInfo;

		// 构造请求头，包含 code、encryptedData 和 iv
		var code = wxLoginResult.code; //用户登录返回的code
		var encryptedData = wxLoginResult.encryptedData; 
		var iv = wxLoginResult.iv;
		var header = {};

		header[constants.WX_HEADER_CODE] = code;
		header[constants.WX_HEADER_ENCRYPTED_DATA] = encryptedData;
		header[constants.WX_HEADER_IV] = iv;

		// 请求服务器登录地址，获得会话信息
		uni.request({
			url: options.loginUrl,
			header: header,
			method: options.method,
			data: options.data,
			success: function(result) {
				var data = result.data;

				// 成功地响应会话信息
				if (data && data[constants.WX_SESSION_MAGIC_ID]) {
					if (data.session) {
						data.session.userInfo = userInfo;
						Session.set(data.session);
						options.success(userInfo);
					} else {
						var errorMessage = '登录失败(' + data.error + ')：' + (data.message || '未知错误');
						var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage);
						options.fail(noSessionError);
					}

					// 没有正确响应会话信息
				} else {
					var errorMessage = '登录请求没有包含会话响应，请确保服务器处理 `' + options.loginUrl + '` 的时候正确使用了 SDK 输出登录结果';
					var noSessionError = new LoginError(constants.ERR_LOGIN_SESSION_NOT_RECEIVED, errorMessage);
					options.fail(noSessionError);
				}
			},

			// 响应错误
			fail: function(loginResponseError) {
				var error = new LoginError(constants.ERR_LOGIN_FAILED, '登录失败，可能是网络错误或者服务器发生异常');
				options.fail(error);
			},
		});
	});

	var session = Session.get();
	if (session) {
		uni.checkSession({
			success: function() {
				options.success(session.userInfo);
			},

			fail: function() {
				Session.clear();
				doLogin();
			},
		});

	} else {
		doLogin();
	}
};

var setLoginUrl = function(loginUrl) {
	defaultOptions.loginUrl = loginUrl;
};

module.exports = {
	LoginError: LoginError,
	login: login,
	setLoginUrl: setLoginUrl,
};
